module(..., package.seeall)

testMode = false
-- 如果是模拟器启动测试模式
if lvgl.indev_get_emu_key then
    testMode = true
end

-- ==================
-- 占卜 
-- ==================
function oracle()
    local oracleMsg = {
        {
            "乾为天", "困龙得水", "上上", "龙腾活理闲沙漠", "曾受虾戏在人间",
            "已到雷声风雨至", "五湖四海都平安",
        }, {
            "坤为地", "饿虎得食", "上上", "饿虎得食喜气欢", "求名应试主高迁",
            "出门吉利行人到", "是非口舌不相干",
        }, {
            "水雷屯", "乱丝无头", "下下", "乱丝无头实难得", "逢着闲事且暂推",
            "交易求财无好处", "谋贵求财心不遂",
        }, {
            "山水蒙", "小鬼偷钱", "中下", "古之此卦犯小耗", "谋望求财空过桥",
            "婚姻合伙有人破", "交易出行受煎熬",
        }, {
            "水天需", "明珠出土", "中上", "土里现出明珠来", "口舌官司消散开",
            "走失行人当见面", "交易有成永无灾",
        }, {
            "天水讼", "二人争路", "中下", "心中有事事难做", "恰是二人争路走",
            "雨下俱是要占先", "谁肯让谁走一步",
        }, {
            "地水师", "马到成功", "中上", "马到成功喜气扬", "求名取利大吉昌",
            "婚姻合伙夫妨碍", "交易出行也顺当",
        }, {
            "水地比", "船得顺风", "上上", "船得顺风不可停", "欲向何方任意行",
            "交易求财大得利", "一切谋望事有成",
        }, {
            "风天小畜", "密云不雨", "下下", "浓云密排下雨难", "盼望生人不见还",
            "交易出厅空费力", "婚姻求财是枉然",
        }, {
            "天泽履", "凤鸣歧山", "中上", "凤鸣歧山闯四方", "占着遂之大吉昌",
            "走失行人有音信", "生意合伙入时多",
        }, {
            "地天泰", "喜报三元", "上上", "喜报三元运气强", "谋望求财大吉祥",
            "交易出行多得意", "是显而易见口舌皆无妨",
        }, {
            "天地否", "虎落深坑", "中中", "虎落深坑不堪言", "进前容易后退难",
            "课堂不遂求则化", "疾病口舌是牵连",
        }, {
            "天火同人", "仙人指路", "中上", "仙人指路大运通", "劝君任意走西东",
            "交易求财不费力", "婚姻合伙有相应",
        }, {
            "火天大有", "砍树摸雀", "上上", "砍树摸雀做事牢", "是非口舌自然消",
            "婚姻合伙不费力", "若问走失未脱逃",
        }, {
            "地山谦", "二人分金", "上上", "二人分金喜气多", "谋望吉庆求和",
            "口舌消散疾病少", "走失行人归家窝",
        }, {
            "雷地豫", "青龙得位", "中中", "青龙得水喜重生", "谋望求财事有成",
            "婚姻出行无阻隔", "是非口舌得安宁",
        }, {
            "泽雷随", "推车靠涯", "中中", "推车靠涯道路干", "谋望求财不费难",
            "婚姻合伙无阻隔", "疾病口舌得安然",
        }, {
            "山风蛊", "推磨岔道", "中中", "推磨岔道远不齐", "疾病口舌犯忧虑",
            "婚姻合伙心改变", "走失不定在哪里",
        }, {
            "地泽临", "发政施仁", "中上", "发政施仁志量高", "出外求财任逍遥",
            "交易婚姻大有意", "走失行人有音耗",
        }, {
            "风地观", "旱荷得水", "中上", "此卦有水来浇荷", "生意买卖利息多",
            "婚姻自有人来助", "出门永不受折磨",
        }, {
            "火雷噬嗑", "饥人遇食", "上上", "饥人遇食喜重来", "凡事称心巧安排",
            "疾病口舌消除散", "生意合伙大发财",
        }, {
            "山火贲", "喜气盈门", "中上", "课逢吉神在运中", "总有凶号不为凶",
            "婚姻合伙渐渐好", "生意财源日日增",
        }, {
            "山地剥", "莺鹊同林", "中下", "莺鹊同林不相合", "占着逢之琐碎多",
            "恩人无义反为怨", "是非平地起风波",
        }, {
            "地雷复", "夫妻反目", "下下", "夫妻反目不顺情", "卦占谋望未有成",
            "官司惊恐财帛散", "若问家宅不安宁",
        }, {
            "天雷无妄", "鸟被笼牢", "下下", "鸟被笼牢难出头", "占者逢之无自由",
            "谋望求财难定准", "疾病口舌怨忧愁",
        }, {
            "山天大畜", "阵势得开", "中上", "此卦占之带六合", "疾病口舌渐渐没",
            "婚姻合伙皆如意", "谋望求财无差错",
        }, {
            "山雷颐", "渭水访贤", "上上", "文王访贤在渭滨", "谋望求财皆随心",
            "交易出行方如意", "疾病口舌皆离身",
        }, {
            "泽风大过", "夜梦金钱", "中下", "夜梦金银醒来空", "求名求利大不通",
            "婚姻难成交易散", "走失之人未见踪",
        }, {
            "坎为水", "水底捞月", "下下", "水底明月不可捞", "占有逢之运不高",
            "交易出行难获利", "走失行人无音耗",
        }, {
            "离为火", "天官赐福", "中上", "来人占卦遇天官", "必然福禄降人间",
            "一切谋望皆占庆", "忧愁满消散主平安",
        }, {
            "泽山咸", "萌芽出土", "中上", "脚踏棒槌转悠悠", "时运不来莫强求",
            "幸得今日时运转", "自有好事在后头",
        }, {
            "雷风恒", "鱼来撞网", "中上", "鱼来撞网乐自然", "卦占行人不久还",
            "交易出行两成就", "谋望事成不费难",
        }, {
            "天山遁", "浓云蔽日", "下下", "浓云遮日不见明", "劝君且莫出远行",
            "婚姻求财皆不利", "提防口舌到门庭",
        }, {
            "雷天大壮", "工师得木", "上上", "工师得木喜重重", "买卖求财大亨通",
            "婚姻合伙皆如意", "一切谋望俱成功",
        }, {
            "火地晋", "锄地得金", "中上", "锄地得金卦如何", "占者逢之喜气多",
            "谋事注财皆如意", "婚姻有成病消没",
        }, {
            "地火明夷", "过河拆桥", "中下", "过河折桥事堪伤", "交易出行有灾殃",
            "谋望求财空费力", "婚姻合伙不相当",
        }, {
            "风火家人", "镜里观花", "下下", "镜里观花休认真", "谋望求财不遂心",
            "交易慢成婚姻合", "走失行人无音信",
        }, {
            "火泽睽", "贩猪卖羊", "下下", "贩买猪羊运不遂", "卦见此人不见回",
            "交易出行无好处", "婚姻求财且莫为",
        }, {
            "水山蹇", "雨雪满途", "下下", "雨雪满途甚泥泞", "交易出行道不通",
            "疾病难治婚姻慢", "谋望求财事难成",
        }, {
            "雷水解", "五关脱难", "中上", "五关脱难运抬头", "难君须当把财求",
            "交易出行有人助", "疾病口舌不须愁",
        }, {
            "山泽损", "推车掉耳", "下下", "时运不至费心多", "比作推车受折磨",
            "山路崎岖掉下耳", "左插右安安不着",
        }, {
            "风雷益", "枯木开花", "上上", "枯木开花渐渐荣", "主人事业大兴隆",
            "婚姻求财大吉庆", "口舌疾病得安宁",
        }, {
            "泽天夬", "游蜂脱网", "上上", "游蜂脱网喜无边", "添财进口福禄连",
            "外财通达内财顺", "富贵荣华胜以前",
        }, -- "姤", "萃" 不在 GB2312 这两个字显示不出来的...
        {
            "天风姤", "他乡遇友", "上上", "他乡遇友喜气欢", "须知运气福重添",
            "自今交了顺当运", "向后管保不相干",
        }, {
            "泽地萃", "鲤鱼变龙", "中上", "鲤鱼化龙喜气来", "口舌疾病身无灾",
            "忧疑从今都消散", "祸门闭来福门开",
        }, {
            "地风升", "指日高升", "上上", "指日高升气象新", "走失行人有信音",
            "巧名出行遂心好", "疾病口舌皆除根",
        }, {
            "泽水困", "撮梯抽杆", "中下", "今有小人暗来欺", "千方百计商量你",
            "明明前来说好话", "撮上杆去抽了梯",
        }, {
            "水风井", "枯井生泉", "上上", "枯井生泉福禄加", "名声喜气大光华",
            "以前虽昌驳杂日", "向后自然有发达",
        }, {
            "泽火革", "旱苗得雨", "上上", "苗逢旱天渐渐衰", "幸得天恩降雨来",
            "忧去喜来能变化", "谋望求财遂心怀",
        }, {
            "火风鼎", "渔人得利", "上上", "渔翁得利喜自然", "谋旺求财两周全",
            "婚姻合伙双得利", "卦者逢之喜气添",
        }, {
            "震为雷", "金钟夜撞", "中上", "占者逢此撞金钟", "时来运转响一声",
            "谋望求财不费力", "交易出行有大成",
        }, {
            "艮为山", "矮巴够枣", "中下", "矮巴够枣难捞枝", "交易的行人不投机",
            "谋望求财空费力", "婚姻合伙总是虚",
        }, {
            "风山渐", "行走薄冰", "下下", "行人走冰怕冰薄", "交易出行把琢磨",
            "婚姻合伙休大意", "官司口舌需要和",
        }, {
            "雷泽归妹", "缘木求鱼", "下下", "缘木求鱼事多乖", "虽不得鱼后无灾",
            "若是行险弄巧计", "事不遂心枉安排",
        }, {
            "雷火丰", "古镜重明", "上上", "古镜重明甚光显", "主人目下运气转",
            "婚姻求财多吉庆", "走失行人去不远",
        }, {
            "火山旅", "宿鸟焚巢", "下下", "宿鸟焚巢时运低", "交易任你走东西",
            "生意买卖皆不利", "官司口舌被人欺",
        }, {
            "巽为风", "孤舟得水", "中上", "孤舟得水出沙滩", "出外行人把家还",
            "是非中舌皆无碍", "婚姻合伙多周全",
        }, {
            "兑为泽", "趁水和泥", "上上", "趁水和泥泥更匀", "头向有准宜出门",
            "交易婚姻大有意", "走失行人不用寻",
        }, {
            "风水涣", "隔河望金", "下下", "财帛隔着一道河", "岸宽水深摸不着",
            "过交节广吉不应", "目下不必来琢磨",
        }, {
            "水泽节", "斩将卦神", "上上", "太公封神不非凡", "谋望求财不费难",
            "交易合伙大吉庆", "疾病口舌消除安",
        }, {
            "风泽中孚", "俊鸟出笼", "中上", "俊鸟幸得出笼中", "月光灾难大逃遁",
            "寻人费力逃难好", "官司疾病俱无凶",
        }, {
            "雷山小过", "急过独桥", "下下", "独木桥上步难行", "主人心事不安宁",
            "交易合伙宜爽利", "婚姻有成莫停迟",
        }, {
            "水火既济", "金榜题名", "中上", "金榜题名喜气新", "求财到手利婚姻",
            "如今交了顺当运", "步步登高大遂心",
        }, {
            "火水未济", "太岁月建", "中下", "太岁入运事多愁", "婚姻财帛莫强求",
            "交易出行未见好", "走失行人不露头",
        },
    }
    local t = oracleMsg[math.random(1, #oracleMsg)]
    -- 再给一次机会
    if t[3]=="下下" then
        t = oracleMsg[math.random(1, #oracleMsg)]
    end
    return {t[1] .. " " .. t[2], t[3] .. "卦", t[4], t[5], t[6], t[7]}
end

-- ==================
-- 农历 
-- ==================

-- 只能计算 1921~2040 年之间的数据, 超出部分返回 nil 
function nongLi(year, month, day)

    -- 日期一天一变, 所以算好备份, 不要每次计算
    local key = year * 10000 + month * 100 + day
    if nongLiKey == key then
        return nongLiVal
    end
    nongLiKey = key

    -- 天干
    local stg = {"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"}

    -- 地支
    local sdz = {"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"}

    -- 属相
    local ssx = {"鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"}

    -- 日期
    local sday = {
        "初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十", "十一",
        "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十", "廿一", "廿二",
        "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十",
    }

    -- 月份
    local smon = {"正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊"}

    -- 公历每月前面的天数
    local monAdd = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}

    -- 农历数据
    local nlData = {
        2635, 333387, 1701, 1748, 267701, 694, 2391, 133423, 1175, 396438, -- 1921~1930
        3402, 3749, 331177, 1453, 694, 201326, 2350, 465197, 3221, 3402, -- 1931~1940
        400202, 2901, 1386, 267611, 605, 2349, 137515, 2709, 464533, 1738, -- 1941~1950
        2901, 330421, 1242, 2651, 199255, 1323, 529706, 3733, 1706, 398762, -- 1951~1960
        2741, 1206, 267438, 2647, 1318, 204070, 3477, 461653, 1386, 2413, -- 1961~1970
        330077, 1197, 2637, 268877, 3365, 531109, 2900, 2922, 398042, 2395, -- 1971~1980
        1179, 267415, 2635, 661067, 1701, 1748, 398772, 2742, 2391, 330031, -- 1981~1990
        1175, 1611, 200010, 3749, 527717, 1452, 2742, 332397, 2350, 3222, -- 1991~2000
        268949, 3402, 3493, 133973, 1386, 464219, 605, 2349, 334123, 2709, -- 2001~2010
        2890, 267946, 2773, 592565, 1210, 2651, 395863, 1323, 2707, 265877, -- 2011~2020
        1706, 2773, 133557, 1206, 398510, 2638, 3366, 335142, 3411, 1450, -- 2021~2030
        200042, 2413, 723293, 1197, 2637, 399947, 3365, 3410, 334676, 2906, -- 2031~2040
    }

    if not monAdd[month] then
        return ""
    end
    local tmpDay = (year - 1921) * 365 + (year - 1921) / 4 + day + monAdd[month] - 38
    if (((year % 4) == 0) and (month > 2)) then
        tmpDay = tmpDay + 1
    end
    tmpDay = math.floor(tmpDay)
    local isEnd = false
    local m = 0
    local k, n
    while not isEnd do
        if not nlData[m + 1] then
            return ""
        end
        k = nlData[m + 1] < 4095 and 11 or 12
        n = k
        while n >= 0 do
            local nBit = nlData[m + 1]
            for i = 1, n do
                nBit = math.floor(nBit / 2)
            end
            nBit = nBit % 2
            if tmpDay <= (29 + nBit) then
                isEnd = true
                break
            end
            tmpDay = tmpDay - 29 - nBit
            n = n - 1
        end
        if isEnd then
            break
        end
        m = m + 1
    end
    year = 1921 + m
    month = k - n + 1
    day = tmpDay
    if k == 12 and month > nlData[m + 1] / 65536 + 1 then
        month = month - 1
    end
    local tg = stg[(((year - 4) % 60) % 10) + 1]
    local dz = sdz[(((year - 4) % 60) % 12) + 1]
    if not (tg and dz and smon[month] and sday[day]) then
        return ""
    end
    nongLiVal = tg .. dz .. "年" .. smon[month] .. "月" .. sday[day]
    -- ssx[(((year - 4) % 60) % 12) + 1] .. "年"
    return nongLiVal
end

-- 日期测试
-- 己丑年冬月十三
-- 庚申年冬月廿八
-- k = 0
-- for y = 1921, 2040 do
--     for m = 1, 12 do
--         for d = 1, 31 do
--             if not nongLi(y, m, d) then
--                 k = k + 1
--                 -- print(y, m, d)
--             end
--         end
--     end
-- end
-- print("test end", k)
-- print(nongLi(2021, 12, 12))

-- ==================
-- 彩灯 
-- ==================
-- led 灯控制
local function funlr(t, n1, n2, n3, n4)
    return string.char(bit.band(bit.bor(bit.lshift(t[n1], n2), bit.rshift(t[n3], n4)), 0xff))
end

-- 产生一个字节的发送码
local function genByte(databyte)
    -- 每个 t 由6位构成，用8位字节表示，但仅前6位有效
    local t = {}
    for i = 1, 8 do
        t[i] = (bit.band(databyte, bit.lshift(0x01, 8 - i)) == 0) and 0x20 or 0x3E
    end
    return funlr(t, 1, 2, 2, 4) .. funlr(t, 2, 4, 3, 2) .. funlr(t, 3, 6, 4, 0) .. funlr(t, 5, 2, 4, 4) ..
               funlr(t, 6, 4, 7, 2) .. funlr(t, 7, 6, 8, 0)
end

local spiInit = false

function ledFlush(led)
    local send = ""
    if not spiInit then
        spi.setup(spi.SPI_2, 0, 0, 8, 4800000, 1, 0) -- 初始化spi
        spiInit = true
    end
    for i = 1, #led do
        send = send .. genByte(led[i][1] or 0) .. genByte(led[i][2] or 0) .. genByte(led[i][3] or 0)
    end
    spi.send(spi.SPI_2, send)
end
local unlight = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}
function ledClose()
    ledFlush(unlight)
end

function music(name)
    sys.timerStart(audio.play, 100, 0, "FILE", "/lua/" .. name .. ".mp3", 1)
end

-- 数字转大写字符串 eg: 12 => "十二"
function n2n(n)
    -- 做多 99, 不考虑百位
    local t = {[0] = "", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"}
    if n < 11 then
        return t[n] or ""
    else
        -- 十位
        local shi = math.floor(n / 10)
        shi = shi >= 2 and t[shi] or ""
        return shi .. "十" .. t[n % 10]
    end
end

function postMap(lat, lng, type, path, timeout, msg)
    local tmp = path .. "_"
    local req = lat .. "," .. lng .. "," .. type .. ",255,255"
    log.info("req", req, tmp)
    if io.exists(tmp) then
        os.remove(tmp)
    end
    http.request("POST", "http://map.wvvwvw.com/", nil, nil, req, timeout,
    function(result, statusCode, head)
        if result then
            if io.exists(tmp) then
                if io.exists(path) then
                    os.remove(path)
                end
                os.rename(tmp, path)
            else
                log.info("文件不存在")
                sys.publish("GET_MAP", false, path)
            end
        end
        sys.publish("GET_MAP", result, path)
    end, tmp)
end

function getMap(lat, lng, path0, path1)
    lat = lat or ""
    lng = lng or ""
    local timeout = 20 * 1000
    postMap(lat, lng, 0, path0, timeout)
    local f1, msg1 = sys.waitUntil("GET_MAP", timeout + 2000)
    postMap(lat, lng, 1, path1, timeout)
    local f2, msg2 = sys.waitUntil("GET_MAP", timeout + 2000)
    log.info("结果", f1, f2)
    return f1 and f2
end

-- 异或校验和
local function checksum(s)
    if not s or string.len(s) == 0 then
        return 0
    end
    local sum = 0
    for i = 1, #s do
        sum = bit.bxor(sum, string.byte(s, i))
    end
    return string.format("%02X", sum)
end

-- 打印 table
function qtab(tbl, lv)
    lv = lv and lv .. "\t" or ""
    print(lv .. "{")
    for k, v in pairs(tbl) do
        if "string" == type(v) then
            local qv = string.match(string.format("%q", v), ".(.*).")
            v = qv == v and '"' .. v .. '"' or "'" .. v:toHex() .. "'" 
        end
        if type(v) == "table" then
            print(lv .. "\t" .. tostring(k) .. " = ")
            qtab(v, lv)
        else
            print(lv .. "\t" .. tostring(k) .. " = " .. tostring(v))
        end
    end
    print(lv .. "},")
end

-- 北斗
tGB = {}

-- GPS
tGP = {}

-- GPS备份
local _tGP = {}
-- 北斗备份
local _tGB = {}

-- 解析其中的 GSV 数据
local function parseGSV(s)
    local tp, pageN, pageI, total, gsv = string.match(s, "(.*)GSV,(%d+),(%d+),(%d*),(.*)")
    if not (tp == "GB" or tp == "GP") then
        return
    end
    pageN = tonumber(pageN)
    pageI = tonumber(pageI)
    local k = "_t" .. tp
    if pageI == 1 then
        tools[k] = {}
    end
    for id, elv, az, strength in string.gmatch(gsv, "(%d+),(%d*),(%d*),(%d*),") do
        if id then
            tools[k][id] = {elv, az, strength}
        end
    end
    if pageI == pageN then
        local tmp = {}
        for k, v in pairs(tools[k]) do
            tmp[#tmp + 1] = {k, unpack(v)}
        end
        table.sort(tmp, function(v1, v2)
            if v1[4] and v2[4] then
                local s1 = tonumber(v1[4]) or 0
                local s2 = tonumber(v2[4]) or 0
                return s1 > s2
            end
            return false
        end)
        tools["t" .. tp] = tmp
    end
end

-- 解析 GPS 数据
local function parseLine(s)
    -- if not ent then return end
    -- 去除换行， 添加校验
    local line, check = string.match(s, "%$(..GSV,.*)%*(..)\r\n")
    if check == checksum(line) then
        parseGSV(line)
    end
end

isRtk = false
rtkStatus = 0
rtkTab = nil

function openRtk(t)
    if type(t)~="table" then
        return false, "参数异常"
    end
    if not rtk.open then
        return false, "固件授权异常"
    end
    rtos.on(rtos.MSG_RTK_INFO, function(msg)
        log.info("rtk", msg.data)
        if not (msg and type(msg.data)=="string") then
            return 
        end
        -- 定位时间,纬度,经度,定位类型,卫星个数,水平精度因子,海拔高度,异常差值,差分时间,参考站
        local t = {string.match(msg.data, "GGA,(%d+%.%d+),(%d+%.%d+%,[NS]),(%d+%.%d+%,[EW]),(%d),(%d+),([%d%.]*),(.*%,M),(.*%,M),(.-),(.-)%*.*")}
        if #t==10 then
            rtkTab = t
        end
        rtkStatus = msg.status or 0
    end)
    if rtk.open(t)~=0 then
        log.info("err", "rtk open")
    else
        log.info("ok", "rtk open")
    end
    isRtk = true
    return true
end

function setGps(n, b)
    -- 设置 gps
    gps.setUart(n, b, 8, uart.PAR_NONE, uart.STOP_1)
    gps.setNmeaMode(2, function(item)
        print(item)
        parseLine(item)
        if isRtk then
            rtk.write(item)
        end
    end)
end

-- AT+TRANSDATA=4,"LUAT"
-- nvm.set("key", "")
ril.regUrc("+TRANSDATA", function(msg)
    local t = {string.match(msg, "%+TRANSDATA: %d*,(.*)")}
    if t[1] == "LUAT" then
        require "console".setup(uart.USB)
    end
end)

-- 测试用的数据
tGP_ = {{"36", "60", "093", "42"}, {"29", "75", "180", "41"}, {"30", "42", "045", "40"}, {"07", "60", "307", "38"},
     {"10", "51", "292", "37"}, {"02", "34", "234", "36"}, {"04", "35", "123", "32"}, {"16", "49", "200", ""},
     {"05", "13", "253", ""}, {"09", "60", "232", ""}, {"08", "01", "177", ""}, {"06", "52", "205", ""}}
tGB_ = {{"27", "61", "028", "47"}, {"09", "30", "264", "46"}, {"08", "75", "272", "45"}, {"07", "27", "317", "43"},
     {"194", "67", "069", "41"}, {"195", "67", "125", "41"}, {"16", "41", "055", "40"}, {"04", "30", "221", "36"},
     {"199", "53", "169", "35"}, {"01", "05", "186", "32"}, {"26", "16", "084", "20"}, {"193", "08", "168", ""}}